///////////////////
/// mkII - Core ///
///////////////////

#pragma once

namespace mk
{
namespace Core
{
namespace Math
{

MK_FORCEINLINE Vector4ConstValue Add
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(_mm_add_ps( a.r, b.r ));
}

MK_FORCEINLINE Vector4ConstValue Sub
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(_mm_sub_ps( a.r, b.r ));
}

MK_FORCEINLINE Vector4ConstValue Mul
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(_mm_mul_ps( a.r, b.r ));
}

MK_FORCEINLINE Vector4ConstValue Div
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(_mm_div_ps( a.r, b.r ));
}

MK_FORCEINLINE Vector4ConstValue MAdd
(
    Vector4ConstValue a,
    Vector4ConstValue b,
    Vector4ConstValue c
)
{
    return Vector4(_mm_add_ps( _mm_mul_ps( a.r, b.r ), c.r ));
}

MK_FORCEINLINE Vector4ConstValue Sqrt
( 
    Vector4ConstValue v
)
{
    return Vector4(_mm_sqrt_ps( v.r ));
}

MK_FORCEINLINE Vector4ConstValue Reciprocal
(
    Vector4ConstValue v
)
{
    return Vector4(_mm_div_ps( Constants::real4_one, v.r ));
}

MK_FORCEINLINE Vector4ConstValue FastReciprocal
(
    Vector4ConstValue v
)
{
    return Vector4(_mm_rcp_ps( v.r ));
}


MK_FORCEINLINE Vector4ConstValue FastReciprocalSqrt
(
    Vector4ConstValue v
)
{
    return Vector4(_mm_rsqrt_ps( v.r ));
}

MK_FORCEINLINE Vector4ConstValue Mod
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(ModVector4(a.r, b.r));
}

MK_FORCEINLINE Vector4ConstValue Min
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(_mm_min_ps( a.r, b.r ));
}

MK_FORCEINLINE Vector4ConstValue Max
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(_mm_max_ps( a.r, b.r ));
}

MK_FORCEINLINE Vector4ConstValue Floor
(
    Vector4ConstValue v
)
{
    return Vector4(FloorVector4(v.r));
}

MK_FORCEINLINE Vector4ConstValue Ceil
(
    Vector4ConstValue v
)
{
    return Vector4(CeilVector4(v.r));
}

MK_FORCEINLINE Vector4ConstValue Round
(
    Vector4ConstValue v
)
{
    return Vector4(RoundVector4(v.r));
}

MK_FORCEINLINE Vector4ConstValue Or
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(_mm_or_ps( a.r, b.r ));
}

MK_FORCEINLINE Vector4ConstValue And
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(_mm_and_ps( a.r, b.r ));
}

MK_FORCEINLINE Vector4ConstValue XOr
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(_mm_xor_ps( a.r, b.r ));
}

MK_FORCEINLINE Vector4ConstValue Not
(
    Vector4ConstValue a
)
{
    return AndNot( Vector4(Constants::uint_true_mask), a );
}

MK_FORCEINLINE Vector4ConstValue AndNot
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(_mm_andnot_ps( b.r, a.r ));
}

MK_FORCEINLINE Vector4ConstValue Select
(
    Vector4ConstValue m,
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    Vector128r m1 = _mm_and_ps(a.r, m.r);
    Vector128r m2 = _mm_andnot_ps(m.r, b.r);
    return Vector4(_mm_or_ps(m1, m2));
}

MK_FORCEINLINE Vector4ConstValue IsEqualMask
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(_mm_cmpeq_ps(a.r, b.r));
}

MK_FORCEINLINE Vector4ConstValue IsLessMask
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(_mm_cmplt_ps(a.r, b.r));
}

MK_FORCEINLINE Vector4ConstValue IsLessEqMask
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Vector4(_mm_cmple_ps(a.r, b.r));
}

MK_FORCEINLINE bool IsTrue
(
    Vector4ConstValue mask
)
{
    return ( _mm_movemask_ps(mask.r) & 1 ) == 1;
}

MK_FORCEINLINE bool IsFalse
(
    Vector4ConstValue mask
)
{
    return ( _mm_movemask_ps(mask.r) & 1 ) == 0;
}

MK_FORCEINLINE Vector4ConstValue LoadVector1
(
    real32 const* src
)
{
    Vector4 r;
    r.r = _mm_load_ps( src );
    return r;
}

MK_FORCEINLINE real32* StoreVector1
(
    real32*             dst,
    Vector4ConstValue   v
)
{
    _mm_store_ps( dst, v.r );
    return dst;
}

} // namespace Math
} // namespace Core
} // namespace mk

